package org.flashbrighton.as3bots.display
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.MouseEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.FileFilter;
	import flash.net.FileReference;
	import flash.net.FileReferenceList;
	import flash.utils.getQualifiedClassName;
	
	import org.flashbrighton.as3bots.bots.BaseBot;
	import org.flashbrighton.as3bots.display.templates.BotDescriptionRow;
	import org.flashbrighton.as3bots.display.templates.LoadBotTemplate;
	import org.flashbrighton.as3bots.utils.BotLoader;
	import org.flexunit.runner.FlexUnitCore;
	import org.madmatt.tdd.LogListener;
	
	public final class LoadBotPage extends Sprite
	{
		
		protected var fileRefList : FileReferenceList;
		protected var botLibrary : Vector.<BaseBot> = new Vector.<BaseBot>;
		protected var bots : Vector.<BaseBot> = new Vector.<BaseBot>;
		protected var champions : Vector.<BaseBot> = new Vector.<BaseBot>;
		
		protected var template : LoadBotTemplate ;
		
		public function LoadBotPage( botLibrary : Vector.<BaseBot>, bots : Vector.<BaseBot> )
		{
			this.botLibrary = botLibrary;
			this.bots= bots;
			
			addEventListener( Event.ADDED_TO_STAGE , handleAddedToStage );
		}
		
		protected function disableButton( s:Sprite ):void
		{
			s.alpha = 0.2;
			s.mouseEnabled = false;
		}
		
		protected function enableButton( s:Sprite ):void
		{
			s.alpha = 1;
			s.mouseEnabled =true;
		}
		
		protected function refresh():void
		{
			template.libraryBotsContainer.removeChildren();
			template.selectedBotsContainer.removeChildren();
			template.championsBotsContainer.removeChildren();
			
			for each( var bot : BaseBot in botLibrary )
			{
				var botDescription : BotDescriptionRow = new BotDescriptionRow();
				
				botDescription.nameTextField.text = bot.botName
				botDescription.y = template.libraryBotsContainer.numChildren * 20;
				botDescription.buttonMode = true;
				botDescription.addEventListener( MouseEvent.CLICK , handleLibraryRowClick );
				template.libraryBotsContainer.addChild( botDescription );
			}
			
			for each( bot in bots )
			{
				botDescription = new BotDescriptionRow();
				
				botDescription.nameTextField.text = bot.botName
				botDescription.y = template.selectedBotsContainer.numChildren * 20;
				botDescription.buttonMode = true;
				botDescription.addEventListener( MouseEvent.CLICK , handleRowClick );
				template.selectedBotsContainer.addChild( botDescription );
			}

			for each( bot in champions )
			{
				botDescription = new BotDescriptionRow();
				
				botDescription.nameTextField.text = bot.botName
				botDescription.y = template.championsBotsContainer.numChildren * 20;
				botDescription.buttonMode = true;
				botDescription.addEventListener( MouseEvent.CLICK , handleChampionRowClick );
				template.championsBotsContainer.addChild( botDescription );
			}

			
			if( bots.length >= 2 ) enableButton( template.startButton );
			else disableButton( template.startButton )
			
		}
		
		protected function onPersonalBotLoad( bot:  BaseBot, botTestClass:Class ):void
        {
			if(!checkTDD(botTestClass)){
				debug("Robot '" + flash.utils.getQualifiedClassName(bot) + "' does not meet TDD acceptance criteria !");
				return;
			}
        	botLibrary.push( bot);
        	if( botLibrary.length > 10 ) botLibrary.shift();

        	refresh();
        }
		
		
		/**
		 * Return true if test exists and are all ok
		 */
		private function checkTDD(botTestClass:Class):Boolean
		{
			var fu_core:FlexUnitCore = new FlexUnitCore();
			var listener:LogListener = new LogListener(template.debugTextField);
			fu_core.addListener(listener);
			fu_core.run(botTestClass);
			return listener.nbTests>0 && listener.nbFailures==0;
		}
		
        protected function onPersonalBotLoadFailure( error : String ):void
        {
        	debug( error );
        }

		public function handleAddedToStage( e : Event ):void
		{
			addChild( template = new LoadBotTemplate( stage.stageWidth, stage.stageHeight ) );
			template.loadButton.addEventListener( MouseEvent.CLICK, handleLoadClick );
			template.startButton.addEventListener( MouseEvent.CLICK, handleStartClick );
			disableButton( template.startButton );
			refresh();
			
			
		}
		
				
		protected function handleLoadClick(e:Event):void
		{
			fileRefList = new FileReferenceList();
            fileRefList.addEventListener(Event.SELECT, handleFileSelected);
            fileRefList.addEventListener(Event.CANCEL, handleCancel);
            fileRefList.addEventListener(IOErrorEvent.IO_ERROR, handleIOError);
            fileRefList.addEventListener(SecurityErrorEvent.SECURITY_ERROR,
                        handleSecurityError);
            var textTypeFilter:FileFilter = new FileFilter("Compiled Bot (*.swf)",
                        "*.swf");
            fileRefList.browse([textTypeFilter]);
		}
		
		protected function handleStartClick( e:Event ):void
		{
			dispatchEvent( new Event( Event.COMPLETE ) );
		}
		
		protected function handleLibraryRowClick( e:MouseEvent ):void
		{
			if( bots.length > 10 ) {
				debug("Arena is full !");
				return;
			}
			var i : int = template.libraryBotsContainer.getChildIndex( e.target as DisplayObject );
			bots.push( botLibrary[i]);
			botLibrary.splice(i,1);
			refresh();
		}
		
		protected function handleChampionRowClick( e:MouseEvent ):void
		{
			if( bots.length > 10 ) {
				debug("Arena is full !");
				return;
			}
			var i : int = template.championsBotsContainer.getChildIndex( e.target as DisplayObject );
			bots.push( champions[i]);
			champions.splice(i,1);
			refresh();
		}
		
		
		protected function handleRowClick( e:MouseEvent ):void
		{
			var i : int = template.selectedBotsContainer.getChildIndex( e.target as DisplayObject );
			botLibrary.push( bots[i]);
			bots.splice(i,1);
			refresh();
		}

        protected function handleIOError(evt:IOErrorEvent):void
        {
            debug("There was an IO Error.");
        }
        protected function handleSecurityError(evt:Event):void
        {
            debug("There was a security error.");
        }

		public function handleFileSelected(evt:Event):void
        {
			for each (var fileRef:FileReference in fileRefList.fileList) 
			{
				fileRef.addEventListener(ProgressEvent.PROGRESS, handleProgress);
				fileRef.addEventListener(Event.COMPLETE, handleComplete);
				fileRef.load();
			}
        }

        public function handleProgress(evt:ProgressEvent):void
        {
            //debug("Loaded " + evt.bytesLoaded + " of " + evt.bytesTotal + " bytes.");
        }

        public function handleComplete(evt:Event):void
        {
			var file:FileReference = FileReference(evt.target);
        	var botLoader : BotLoader = new BotLoader( file.name.replace(/\.[^.]+$/,'')+'Bot' , onPersonalBotLoad , onPersonalBotLoadFailure );
            debug("File '"+file.name+"' was successfully loaded.");
            botLoader.loadBytes( evt.target.data );

        }

        protected function handleCancel(evt:Event):void
        {
            debug("The browse request was canceled by the user.");
        }

        protected function debug( s:String ):void
        {
        	template.debugTextField.appendText(s+'\n');
        	template.debugTextField.scrollV = template.debugTextField.maxScrollV;
        }

		public function clearArena():void
		{
			bots.splice(0, bots.length);
		}

		public function addChampion(champion:BaseBot):void
		{
			champions.push(champion);
			refresh();
		}

	}
}